home *** CD-ROM | disk | FTP | other *** search
/ LiquidLibrary 2005 September / LiquidLibrary 2005 Sep - Disc 1.iso / pc / Portfolio Browser / Filters / PDF / LIB / gs_cidcm.ps < prev    next >
Text File  |  2003-01-03  |  18KB  |  487 lines

  1. %    Copyright (C) 2000 artofcode LLC.  All rights reserved.
  2. % This software is licensed to a single customer by Artifex Software Inc.
  3. % under the terms of a specific OEM agreement.
  4.  
  5. % $RCSfile$ $Revision$
  6. % Extending Font resource category with CIDFont-CMap fonts.
  7.  
  8. languagelevel 2 .setlanguagelevel currentglobal true setglobal
  9.  
  10.  
  11. % In the comments below, 'CSI' is an abbreviation/acronym for CIDSystemInfo.
  12. % We pre-scan resource files to retrieve the CSI from them.
  13. % First we define a hidden procset .prs_dict containing
  14. % necessary variables and procedures.
  15. % Then we redefine the old /Font category using this procset.
  16.  
  17. % We maintain internal caches for the CSI values retrieved from
  18. % resource files. This supposes that document doesn't uninstall
  19. % resource files. To disable caching, set enable_cache to false.
  20.  
  21. % We suppose that names starting with '.prs' do not appear in resource files.
  22. % If this causes any problem, this prefix should be systematically changed
  23. % in this file.  ('prs' is an abbreviation for 'prescan'.)
  24.  
  25. 25 dict begin
  26.  
  27. % Define local variables :
  28.  
  29. /.prs_dict currentdict def       % self-reference (constant)
  30. /.prs_empty 0 dict readonly def  
  31. /path_buffer 255 string def
  32. /name_buffer 255 string def
  33. /minus (-) 0 get def             % character code constant for '-'
  34. /period (.) 0 get def            % character code constant for '.'
  35. /CMap 10 dict def                % CSI cache for CMaps
  36. /CIDFont 10 dict def             % CSI cache for CIDFonts
  37. /enable_cache true def           % set false to disable cache
  38.  
  39. % The folloving variables are just placeholders for ones to be set
  40. % dynamically :
  41. /.prsFile 0 def                   % file to prescan
  42. /.prsResult 0 def                 % result of prescan
  43. /.prsDictCount 0 def              % save the dictionary stack depth
  44.  
  45. % Define a dummy CIDInit procset to use while pre-scanning :
  46.  
  47. /DummyCIDInit 15 dict 
  48. begin
  49.  
  50.   /begincmap {} def
  51.   /usecmap {pop} bind def
  52.  
  53.   {stop} bind
  54.   [ /begincodespacerange /endcodespacerange /beginnotdefchar /endnotdefchar
  55.     /beginnotdefrange /endnotdefrange /begincidchar /endcidchar /begincidrange 
  56.     /endcidrange /endcmap /usefont /StartData
  57.   ] {
  58.     1 index def
  59.   } bind forall
  60.   pop
  61.  
  62. currentdict end def
  63.  
  64. % Define a local 'findresource' for pre-scanning :
  65. % (it returns the dummy CIDInit instead of the regular CIDInit ProcSet)
  66.  
  67. /findresource { % <InstName> <CatName> findresource <inst>
  68.   2 copy /ProcSet eq exch             % /InstName /CatName bool /InstName
  69.   /CIDInit eq and {
  70.     pop pop //DummyCIDInit
  71.   } {
  72.     //findresource exec
  73.   } ifelse
  74. } bind def
  75.  
  76. % Define procedures for pre-scanning :
  77.  
  78. /StopIfCSIDefined {   % - StopIfCSIDefined -
  79.   
  80.   % Check if the dictionary stack contains a dictionary containing /CIDSystemInfo. 
  81.   % The search is limited to the top .prsDictCount dictionaries in the stack.
  82.   % If so, retrieve the CSI, and execute stop to terminate the pre-scanning of the file.
  83.   % Otherwise, do nothing, so the pre-scanning continues.
  84.  
  85.   countdictstack //.prs_dict /.prsDictCount get sub dup {
  86.     currentdict /CIDSystemInfo .knownget {
  87.       //.prs_dict exch /.prsResult exch put
  88.       stop
  89.     } if
  90.     currentdict exch end
  91.   } repeat {
  92.     begin
  93.   } repeat
  94. } bind def
  95.  
  96. /PrescanFile {     % - PrescanFile -
  97.   { //.prs_dict /.prsFile get token {      
  98.       dup type                          % token type
  99.       dup /nametype eq exch /operatortype eq or {
  100.         dup xcheck {
  101.           exec
  102.           //StopIfCSIDefined exec
  103.         } if
  104.       } if
  105.     } {
  106.       stop
  107.     } ifelse
  108.   } loop
  109. } bind odef
  110.  
  111. /GetCIDSystemInfoFromFile { % <file> GetCIDSystemInfoFromFile <CSI>
  112.   
  113.   % This procedure reads resource files with 'token',
  114.   % executing the tokens untill /CIDSystemInfo appears to be defined.
  115.   % Normally the resource file creates a new dictionary on
  116.   % dictionary stack and defines /CIDSystemInfo in it.
  117.   %
  118.   % Returns an empty dictionary if no CIDSystemInfo is found.
  119.  
  120.   //.prs_dict begin
  121.   /.prsFile exch def
  122.   /.prsResult //.prs_empty def
  123.   /.prsDictCount countdictstack def
  124.   { //PrescanFile } stopped pop
  125.   //.prs_dict /.prsResult get
  126.   end
  127. } bind def
  128.  
  129. /GetCIDSystemInfo {     % <InstName> <CatName> GetCIDSystemInfo <CSI>
  130.   
  131.   % Retrieve CSI, using caches.
  132.   
  133.   2 copy resourcestatus {
  134.     pop 2 lt {
  135.       findresource /CIDSystemInfo .knownget not {
  136.         //.prs_empty
  137.       } if
  138.     } {                                                      
  139.       dup //.prs_dict exch get                % /InstName /CatName CSIs
  140.       dup 3 index known
  141.       //enable_cache and {                            
  142.         exch pop exch get                     % CSI
  143.       } {                                                  
  144.         3 1 roll                              % CSIs /InstName /CatName
  145.         /Category findresource begin          % CSIs /InstName
  146.         dup //path_buffer ResourceFileName    % CSIs /InstName (path)
  147.         end                                   
  148.         currentglobal exch true setglobal     % CSIs /InstName g
  149.         mark exch                             % CSIs /InstName g [ (path)
  150.         { (r) file                            % CSIs /InstName g [ file
  151.           //GetCIDSystemInfoFromFile exec     % CSIs /InstName g [ CSI
  152.         } stopped {
  153.           cleartomark //.prs_empty             
  154.         } {
  155.           exch pop
  156.         } ifelse                              % CSIs /InstName g CSI
  157.         exch setglobal                        % CSIs /InstName CSI
  158.         dup 4 1 roll                          % CSI CSIs /InstName CSI
  159.         put                                   % CSI
  160.       } ifelse
  161.     } ifelse
  162.   } {
  163.     pop pop //.prs_empty
  164.   } ifelse
  165. } bind def
  166.  
  167. /IsCompatibleCSI {  % <CSI-M> <CSI-F> IsCompatibleCSI <bool>
  168.   
  169.   % The CSI in a CIDFont may be an array, a dict, or null.
  170.   % If it is an array, it must be of 1 element, which is a dict.
  171.   % In this case the dict is used for testing the compatibility.
  172.   % Two dicts are compatible iff they contain same /Ordering and /Registry.
  173.  
  174.   exch                                  % CSI-F CSI-M
  175.   { dup type /arraytype eq {
  176.       dup length 1 ne {
  177.         pop pop false exit
  178.       } if
  179.       0 get
  180.     } if                                % CSI-F CSI-M
  181.     dup type /dicttype ne {
  182.       pop pop false exit
  183.     } if                                % CSI-F <<CSI-M>>
  184.     exch                                % <<CSI-M>> CSI-F
  185.     dup type /dicttype ne {
  186.       pop pop false exit
  187.     } if                                % <<CSI-M>> <<CSI-F>>
  188.     true                                % <<CSI-M>> <<CSI-F>> bEQ
  189.     [/Registry /Ordering] {                    
  190.       2 index 1 index .knownget not {
  191.         1234567
  192.       } if                              % <<CSI-M>> <<CSI-F>> bEQ /key vF
  193.       exch                              % <<CSI-M>> <<CSI-F>> bEQ vF /key
  194.       4 index exch .knownget not {
  195.         7654321
  196.       } if                              % <<CSI-M>> <<CSI-F>> bEQ vF vM
  197.       eq and                            % <<CSI-M>> <<CSI-F>> bEQ
  198.     } forall
  199.     exch pop exch pop                   % bEQ
  200.     exit
  201.   } loop
  202. } bind def
  203.  
  204. /IsComposedOK {     % <CIDFontName> <CMapName> IsComposedOK <bool>
  205.   
  206.   % Check if the given CIDFont and CMap have compatible CSIs.
  207.  
  208.   exch                                  % /CMapName /CIDFontName
  209.   /CIDFont //GetCIDSystemInfo exec      % /CMapName CSI-F
  210.   dup type /dicttype eq {
  211.     dup length 0 ne {                          
  212.       exch                              % CSI-F /CMapName
  213.       /CMap //GetCIDSystemInfo exec     % CSI-F CSI-M
  214.       //IsCompatibleCSI exec            % bool
  215.     } {
  216.       pop pop false
  217.     } ifelse
  218.   } {
  219.     pop pop false
  220.   } ifelse
  221. } bind def
  222.  
  223. /IsComposedFont {   % <FontName> IsComposedFont <CIDFontName> <CMapName> true
  224.                     % <FontName> IsComposedFont false
  225.   
  226.   % Check if the given font name may be decomposed into CIDFont.CMap, CIDFont-CMap
  227.   % or into CIDFont--CMap, such that CIDFont and CMap have compatible CSIs.
  228.                                         % FontName
  229.   dup type /stringtype ne {
  230.     //name_buffer cvs
  231.   } if                                  % (FontName)
  232.   { dup length 2 sub -1 1 {
  233.                                         % (FontName) i
  234.       2 copy get dup //minus eq exch //period eq or {                
  235.         2 copy 2 copy                   % (FontName) i (FontName) i (FontName) i
  236.         2 copy get //minus eq {
  237.           2 copy 1 sub get //minus eq {
  238.             1 sub
  239.           } if
  240.         } if                            % (FontName) i (FontName) i (FontName) i0
  241.         0 exch getinterval cvn          % (FontName) i (FontName) i /CIDFontName
  242.         3 1 roll                        % (FontName) i /CIDFontName (FontName) i
  243.         1 add dup                       % (FontName) i /CIDFontName (FontName) i1 i1
  244.         5 index length                  % (FontName) i /CIDFontName (FontName) i1 i1 l
  245.         exch sub getinterval cvn        % (FontName) i /CIDFontName /CMapName
  246.         2 copy //IsComposedOK exec {    % (FontName) i /CIDFontName /CMapName 
  247.           4 2 roll pop pop              % /CIDFontName /CMapName
  248.           stop
  249.         } if
  250.         pop pop pop
  251.       } {
  252.         pop
  253.       } ifelse                          % (FontName)
  254.     } for
  255.     pop
  256.   } stopped
  257. } bind def
  258.  
  259. /ComposeName { % <CIDFont> <CMap> <scr> ComposeName <CIDFont-CMap>
  260.   dup dup 5 2 roll                        % (scr) (scr) /CIDFont /CMap (scr)
  261.   3 2 roll exch cvs length dup            % (scr) (scr) /CMap l0 l0
  262.   4 -1 roll exch //minus put              % (scr) /CMap l0
  263.   1 add dup                               % (scr) /CMap l1 l1
  264.   3 index dup length                      % (scr) /CMap l1 l1 (scr) L
  265.   2 index sub                             % (scr) /CMap l1 l1 (scr) LT
  266.   3 2 roll                                % (scr) /CMap l1 (scr) LT l1
  267.   exch getinterval                        % (scr) /CMap l1 (scrT)
  268.   3 2 roll exch cvs length                % (scr) l1 l2
  269.   add 0 exch getinterval                  % (CIDFont-CMap)
  270. } bind def
  271.  
  272.  
  273. % Define a few procedure templates to be modified dynamically :
  274.  
  275. currentpacking false setpacking
  276.  
  277. /BindAux {   % <proc> BindAux <proc>
  278.   0 exec
  279. } bind def
  280.  
  281. /EnumerateFontNames { %  - EnumerateFontNames ...
  282.   
  283.   % This is a pattern for enumeration procedure to be built dynamically,
  284.   % using Bind with a temporary dictionary.
  285.   % The following names will be replaced with specific objects
  286.   % during Bind : en_local_dict, scr, proc, Fonts, Category .
  287.  
  288.   end % Category
  289.   { 
  290.     0 1 2 {
  291.       en_local_dict exch /status exch put
  292.       Fonts {                                            
  293.         en_local_dict /status get eq {            
  294.           scr cvs                           % ... (Font)
  295.           proc exec                         %
  296.         } {
  297.           pop
  298.         } ifelse                            % ...
  299.       } forall
  300.     } for                                   % ...
  301.   } stopped
  302.   Category begin
  303.   { stop } if
  304. } bind def
  305.  
  306. setpacking
  307.  
  308. /Bind {    % <proc> Bind <proc>
  309.   
  310.   % Make a copy of the given procedure, binding in the values of all names
  311.   % defined in currentdict.
  312.   % Caution : this code cannot handle procedures that were already
  313.   % bound recursively.
  314.  
  315.   dup length array copy
  316.   dup length 1 sub -1 0 {                      
  317.     2 copy get                            % {precopy} i {elem}
  318.     dup dup type /arraytype eq exch xcheck and {
  319.                                           % {precopy} i {elem}
  320.       //BindAux exec                      % {precopy} i {elem_copy}
  321.       2 index 3 1 roll put                % {precopy}
  322.     } {
  323.       dup dup type /nametype eq exch xcheck and {
  324.                                           % {precopy} i {elem}
  325.         currentdict exch .knownget {            
  326.           2 index 3 1 roll put            % {precopy}
  327.         } {                                            
  328.           pop
  329.         } ifelse
  330.       } {
  331.         pop pop
  332.       } ifelse
  333.     } ifelse                              % {precopy}
  334.   } for                                   % {copy}
  335.   cvx
  336. } bind def
  337.  
  338. //BindAux 0 //Bind put   % bind the recursive call in 'Bind'.
  339.  
  340.  
  341.  
  342. % Redefine the /Font category with CIDFont-CMap construction :
  343.  
  344. % The following code supposes that the following names are not
  345. % defined in the old /Font category dictionary :
  346. % /IsComposedFont, /Bind, /IsComposedOK, /EnumerateFontNames .
  347.  
  348.  
  349. /Font /Category findresource dup length dict copy begin
  350.  
  351. /FindResource {  % <InstName> FindResource <inst>
  352.   dup //ResourceStatus exec {
  353.     pop pop //FindResource exec
  354.   } {                                                
  355.     dup //IsComposedFont exec {          % /FontName /CIDFontName /CMapName 
  356.       exch [ exch ] composefont          % inst
  357.     } {
  358.       //FindResource exec
  359.     } ifelse
  360.   } ifelse
  361. } bind def
  362.  
  363. /ResourceStatus {  % <InstName> ResourceStatus <nStatus> <nSize> true
  364.                    % <InstName> ResourceStatus false
  365.   dup //ResourceStatus exec {                    
  366.     3 2 roll pop true                     % nStatus nSize true
  367.   } {                                                  
  368.     //IsComposedFont exec {               % /CIDFontName /CMapName 
  369.       /CMap resourcestatus {              % /CIDFontName nStatusM nSizeM 
  370.         exch pop exch                     % nSizeM /CIDFontName 
  371.         /CIDFont resourcestatus {         % nSizeM nStatusF nSizeF 
  372.           exch pop                        % nSizeF nSizeM
  373.           dup 0 ge {
  374.             exch dup 0 ge {
  375.               add
  376.             } {
  377.               exch pop
  378.             } ifelse
  379.           } {
  380.             pop
  381.           } ifelse                        % nSize
  382.           2 exch true                     % nStatus nSize true
  383.         } {                        
  384.           pop pop pop false  % work around buggy resource file
  385.         } ifelse
  386.       } {                            
  387.         pop pop pop false    % work around buggy resource file
  388.       } ifelse
  389.     } {
  390.       false
  391.     } ifelse
  392.   } ifelse
  393. } bind def
  394.  
  395. /ResourceForAll { % <template> <proc> <scratch> ResourceForAll - 
  396.  
  397.   % We suppose that the resourceforall procedure does not 
  398.   % define or install new fonts, CMaps, and/or CIDFonts.
  399.  
  400.   % First we create 3 temporary dictionaries to store temporary data
  401.   % about fonts, CMaps and CIDFonts.
  402.   % These dictionaries must be created dynamically, to allow for a possible 
  403.   % recursive call to resourceforall from the resourceforall procedure.
  404.  
  405.   currentglobal false setglobal
  406.   20 dict 20 dict 20 dict
  407.   4 -1 roll setglobal                     % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  408.  
  409.   % Store resource names into local dictionaries :
  410.  
  411.   5 index [ 2 index {exch cvn dup put} aload pop ] cvx 5 index //ResourceForAll exec
  412.   (*)     [ 3 index {exch cvn dup put} aload pop ] cvx 5 index /CMap resourceforall
  413.   (*)     [ 4 index {exch cvn dup put} aload pop ] cvx 5 index /CIDFont resourceforall
  414.  
  415.   %% Make the list of fonts in the form (/Name status) :
  416.  
  417.                                           % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  418.   dup {                                              
  419.     //ResourceStatus exec {                        
  420.       pop 2 index                         % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>> /Name nStatus <<Font>>
  421.       3 1 roll put                        % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  422.     } {
  423.       pop
  424.     } ifelse
  425.   } forall                                % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
  426.  
  427.   %% Add CIDFont-CMap to it (filtering duplicates) :
  428.  
  429.   3 2 roll  {                                        
  430.     3 index {                                        
  431.       3 1 roll                            % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /CIDFont /CMap
  432.       6 index //ComposeName exec          % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap (Font)
  433.       dup 8 index .stringmatch {              
  434.         cvn                               % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font
  435.         dup 4 index exch known {
  436.           pop pop
  437.         } {                                            
  438.           2 index                         % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font /CIDFont
  439.           4 2 roll                        % (templ) proc (scr) <<CMap>> <<Font>> /Font /CIDFont /CIDFont /CMap
  440.           //IsComposedOK exec {                
  441.             exch 2 index exch 2 put       % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont
  442.           } {
  443.             exch pop
  444.           } ifelse
  445.         } ifelse
  446.       } {
  447.         pop pop
  448.       } ifelse
  449.       dup                                 % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CIDFont
  450.     } forall
  451.     pop pop                               % (templ) proc (scr) <<CMap>> <<Font>>
  452.   } forall                                % (templ) proc (scr) <<CMap>> <<Font>>
  453.   exch pop                                % (templ) proc (scr) <<Font>>
  454.  
  455.   % Build the enumeration procedure :
  456.  
  457.   % Since the resourceforall procedure may leave values on the operand stack,
  458.   % we cannot simply store the enumerator's local data on the stack.
  459.   % We also cannot use a static dictionary to store local variables,
  460.   % because of possible recursion in the resourceforall procedure.
  461.   % To work around this, we create a copy of the enumeration procedure and
  462.   % bind it dynamically with a temporary dictionary, which contains
  463.   % local variables for the currently executing instance of resourceforall.
  464.  
  465.   currentdict
  466.   6 dict begin % the temporary dictionary
  467.     /Category exch def
  468.     /Fonts exch def
  469.     /scr exch def
  470.     /proc exch def
  471.     /en_local_dict currentdict def
  472.     //EnumerateFontNames //Bind exec      % (templ) Enumerator
  473.     /status 0 def % variable for the current status to enumerate - do not Bind with it !
  474.   end
  475.   exch pop                                % Enumerator
  476.  
  477.   % Do the enumeration :
  478.  
  479.   exec
  480. } bind def
  481.  
  482.  
  483. currentdict end /Font exch /Category defineresource pop
  484. end
  485. setglobal .setlanguagelevel
  486.